import * as fs from 'fs';
import * as path from 'path';
import * as ejs from 'ejs';
import type {
  SwaggerApi,
  SwaggerData,
  SwaggerSchema,
  MethodRequest,
  SwaggerItem,
} from './modules/types';
import * as utils from './modules/utils';
import * as formatter from './modules/formatter';
import * as prettierEslint from 'prettier-eslint';
import fetch from 'node-fetch-commonjs';

// const url = process.argv[2];
// if (!url) {
//   console.error('请提供一个有效的URL');
//   process.exit(1);
// }
const url = "http://8.134.250.251:2284/api-docs/json";
const apisPath = path.resolve('src', 'apis', 'apis.ts');
const requestPath = path.resolve('src', 'types', 'request.d.ts');
const responsePath = path.resolve('src', 'types', 'response.d.ts');

const formate = async (options: { text: string; filePath: string }) => {
  // eslint-disable-next-line
  // @ts-ignore-next-line
  return await prettierEslint(options);
  // return options.text
};

const getData = async (url: string) => {
  try {
    if (fs.existsSync(url)) {
      const fileContent = fs.readFileSync(url, 'utf-8');
      return JSON.parse(fileContent) as SwaggerData;
    } else {
      const res = await fetch(url);
      // const data = await res.json();
      // 请求后做utf-8编码
      const data = JSON.parse(await res.text()) as SwaggerData;
      return data as SwaggerData;
    }
  } catch {
    console.error('获取数据失败');
    return undefined;
  }
};

const checkGeneric = (schema: string) => {
  let str = schema;
  const path: string[] = [];
  while (true) {
    const match = str.match(
      /^(ResponseDataList|ResponseData|ResponseList|RespData|ListData)(.+)$/,
    );
    if (!match) break;
    str = match[2];
    path.push(match[1]);
  }
  if (/^Void\d*$/.test(str)) str = 'never';
  return { schema: formatter.typeName(str), path };
};

const methodList = ['get', 'post', 'put', 'delete', 'patch'] as const;
const getRequest = (
  url: string,
  api: MethodRequest,
  method: (typeof methodList)[number],
) => {
  const apiInfo = api.summary || '';
  const rest = api.parameters?.filter(
    (item) => !['path', 'query', 'header'].includes(item.in),
  );
  if (rest?.length) console.log('存在未处理的parameters:', url);
  const data = api.requestBody?.content?.['application/json']?.schema;
  // let formData = api.requestBody?.content?.['multipart/form-data']?.schema;
  let formData: SwaggerSchema | undefined;

  let query = api.parameters?.filter((item) => item.in === 'query');
  if (
    query &&
    query.some(
      (item) =>
        item?.schema?.type === 'string' && item?.schema?.format === 'binary',
    )
  ) {
    console.log('存在query参数中有文件上传:', url);
    if (formData) {
      if (!formData.properties) formData.properties = {};
      for (const item of query) {
        const key = item.name;
        const swaggerItem: SwaggerItem = {
          description: item.description,
          ...item.schema,
        };
        formData.properties[key] = swaggerItem;
      }
    } else {
      formData = {
        title: 'FormData',
        type: 'object',
        required: query
          .filter((item) => item.required)
          .map((item) => item.name),
        properties: {},
      };
      for (const item of query) {
        const key = item.name;
        const swaggerItem: SwaggerItem = {
          description: item.description,
          ...item.schema,
        };
        formData.properties![key] = swaggerItem;
      }
    }
    query = undefined;
  }

  return {
    apiInfo,
    url,
    method,
    path: api.parameters?.filter((item) => item.in === 'path'),
    query,
    header: api.parameters?.filter((item) => item.in === 'header'),
    data,
    formData,
    response: utils.getResponse(url, api),
  };
};

const getApis = (data: SwaggerData) => {
  const paths = data.paths;
  const apis: SwaggerApi[] = [];

  for (const url in paths) {
    const api = paths[url];
    for (const method of methodList) {
      if (!api[method]) continue;
      // let prefix = '';
      // prefix = '/business/v1';
      // if (!api[method].tags?.some((tag) => tag.includes('business'))) {
      //   continue;
      // }
      const item = getRequest(url, api[method], method);
      if (item) apis.push(item);
    }
  }
  return apis;
};

const getSchemas = (data: SwaggerData) => {
  const schemas = data.components.schemas;
  const schemasList: SwaggerSchema[] = [];
  const genericList: { schema: string; title: string; path: string[] }[] = [];
  for (const schemaName in schemas) {
    const item = schemas[schemaName];
    const { schema, path } = checkGeneric(schemaName);
    if (path.length) {
      genericList.push({ schema: schemaName, title: schema, path });
    } else if (schema === 'ResponseData') {
      continue;
    } else if (schema === 'RespData') {
      continue;
    } else {
      schemasList.push({ ...item, title: formatter.interfaceName(schemaName) });
    }
  }
  return { schemasList, genericList };
};

const apisTemplate = fs.readFileSync('server/templates/apis.ejs', 'utf-8');
const responseTemplate = fs.readFileSync(
  'server/templates/response.ejs',
  'utf-8',
);
const requestTemplate = fs.readFileSync(
  'server/templates/request.ejs',
  'utf-8',
);

const run = async () => {
  const data = await getData(url);
  if (!data) return;
  const { schemasList, genericList } = getSchemas(data);
  const apis = getApis(data);
  // fs.writeFileSync("apis.json", JSON.stringify(apis, null, 2))
  // fs.writeFileSync("schemasList.json", JSON.stringify(schemasList, null, 2))
  // fs.writeFileSync("genericList.json", JSON.stringify(genericList, null, 2))
  const apisStr = ejs.render(apisTemplate, {
    apis,
    schemasList,
    genericList,
    utils,
    formatter,
  });
  formatter.clearNameMap();
  const responseStr = ejs.render(responseTemplate, {
    apis,
    schemasList,
    genericList,
    utils,
    formatter,
  });
  formatter.clearNameMap();
  const requestStr = ejs.render(requestTemplate, {
    apis,
    schemasList,
    genericList,
    utils,
    formatter,
  });

  const formattedApis = await formate({ text: apisStr, filePath: apisPath });
  fs.writeFileSync(apisPath, formattedApis, { encoding: 'utf-8' });

  const formattedResponse = await formate({
    text: responseStr,
    filePath: responsePath,
  });
  fs.writeFileSync(responsePath, formattedResponse, { encoding: 'utf-8' });

  const formattedRequest = await formate({
    text: requestStr,
    filePath: requestPath,
  });
  fs.writeFileSync(requestPath, formattedRequest, {
    encoding: 'utf-8',
  });

  console.log('生成成功');
};

run();
